package com.accenture.fd.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddress;

import com.accenture.fd.utils.generator.model.ClassToExcelModel;
import com.accenture.fd.utils.generator.model.FieldListDTO;
import com.accenture.fd.utils.generator.model.MethodListDTO;

import cn.hutool.poi.excel.WorkbookUtil;

public class ExcelMain {
	private static final String TEMPLATE_PATH = "/doc/仕様書/KKPM_クラス仕様書（自検協情報取得ロジック）.xls"; // 模版路径 (需确认是否放在项目,如果放在项目需要做改动)
	private static final String SHEET_NAME = "WP30206 クラス仕様書"; // sheet名称
	private static final String METHOD = "method";
	private static final String FIELD = "field";
	private int fieldfirstRow = 22;
	private int methodfirstRow = 27;
	private int fieldlastRow = 24;
	private int methodlastRow = 29;

	public static void main(String[] args) {
		ExcelMain excel = new ExcelMain();
		excel.run();
	}

	private void run() {
		ClassToExcelModel ctmModel = mockData();
		registerClass(ctmModel);
	}

	//モックデータ作成
	private ClassToExcelModel mockData() {
		ClassToExcelModel ctmModel = new ClassToExcelModel();
		ArrayList<FieldListDTO> fieldList = new ArrayList<>();
		FieldListDTO fieldListDTO1 = new FieldListDTO();
		fieldListDTO1.setFieldDefinition("Definition1");
		fieldListDTO1.setFieldmiddleRemarks("middleRemarks1");
		fieldListDTO1.setFieldSummary("summary1");
		FieldListDTO fieldListDTO2 = new FieldListDTO();
		fieldListDTO2.setFieldDefinition("Definition2");
		fieldListDTO2.setFieldmiddleRemarks("middleRemarks2");
		fieldListDTO2.setFieldSummary("summary2");
		FieldListDTO fieldListDTO3 = new FieldListDTO();
		fieldListDTO3.setFieldDefinition("Definition3");
		fieldListDTO3.setFieldmiddleRemarks("middleRemarks3");
		fieldListDTO3.setFieldSummary("summary3");
		FieldListDTO fieldListDTO4 = new FieldListDTO();
		fieldListDTO4.setFieldDefinition("Definition4");
		fieldListDTO4.setFieldmiddleRemarks("middleRemarks4");
		fieldListDTO4.setFieldSummary("summary4");
		FieldListDTO fieldListDTO5 = new FieldListDTO();
		fieldListDTO5.setFieldDefinition("Definition4");
		fieldListDTO5.setFieldmiddleRemarks("middleRemarks4");
		fieldListDTO5.setFieldSummary("summary4");
		fieldList.add(fieldListDTO1);
		fieldList.add(fieldListDTO2);
		fieldList.add(fieldListDTO3);
		fieldList.add(fieldListDTO4);
		fieldList.add(fieldListDTO5);
		fieldList.add(fieldListDTO5);
		fieldList.add(fieldListDTO5);
		ctmModel.setFieldList(fieldList);

		ArrayList<MethodListDTO> methodlist = new ArrayList<>();
		MethodListDTO methodListDTO1 = new MethodListDTO();
		methodListDTO1.setFootRemarks("footRemarks1");
		methodListDTO1.setMethodDefinition("methodDefinition1");
		methodListDTO1.setMethodSummary("methodSummary1");
		MethodListDTO methodListDTO2 = new MethodListDTO();
		methodListDTO2.setFootRemarks("footRemarks2");
		methodListDTO2.setMethodDefinition("methodDefinition2");
		methodListDTO2.setMethodSummary("methodSummary2");
		MethodListDTO methodListDTO3 = new MethodListDTO();
		methodListDTO3.setFootRemarks("footRemarks3");
		methodListDTO3.setMethodDefinition("methodDefinition3");
		methodListDTO3.setMethodSummary("methodSummary3");
		MethodListDTO methodListDTO4 = new MethodListDTO();
		methodListDTO4.setFootRemarks("footRemarks4");
		methodListDTO4.setMethodDefinition("methodDefinition4");
		methodListDTO4.setMethodSummary("methodSummary4");
		MethodListDTO methodListDTO5 = new MethodListDTO();
		methodListDTO5.setFootRemarks("footRemarks4");
		methodListDTO5.setMethodDefinition("methodDefinition4");
		methodListDTO5.setMethodSummary("methodSummary4");
		methodlist.add(methodListDTO1);
		methodlist.add(methodListDTO2);
		methodlist.add(methodListDTO3);
		methodlist.add(methodListDTO4);
		methodlist.add(methodListDTO5);
		ctmModel.setMethodList(methodlist);
		ctmModel.setFieldPackageNm("packageName");
		return ctmModel;
	}

	public void registerClass(ClassToExcelModel ctmModel) {

		String filePath = ExportClassController.class.getResource(TEMPLATE_PATH).getPath();

		InputStream is = null;
		try {
			String path = URLDecoder.decode(filePath, "UTF-8");
			File finalXlsxFile = new File(path);
			is = new FileInputStream(finalXlsxFile);
			Workbook wb = WorkbookFactory.create(is);
			Sheet sheet = WorkbookUtil.getOrCreateSheet(wb, SHEET_NAME);
			// 情報設定
			setDetails(ctmModel, sheet, wb);

			OutputStream out = new FileOutputStream(finalXlsxFile);
			try {
				wb.write(out);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				out.close();
			}
		} catch (IOException | EncryptedDocumentException | InvalidFormatException e) {
			e.printStackTrace();
		}
	}

	private void setDetails(ClassToExcelModel ctmModel, Sheet sheet, Workbook wb) {
		// 共通フィールドを設定
		setClassCommonFiled(ctmModel, sheet);
		// フォーマット
		CellStyle cellStyle = getCellStyle(wb);
		//フィールドサイズ
		int fieldSize = ctmModel.getFieldList().size();
		//フィールドRow追加
		insertRows(fieldlastRow, fieldSize, sheet, FIELD);
		// フィールドを設定
		for (int i = 0; i < fieldSize; i++) {
			setRowInfo(ctmModel, sheet, i, cellStyle, FIELD);
		}
		//メソッドのヘーダ部のフォーマットを設定
		createMethodHead(sheet);
		//フィールドサイズ
		int methodSize = ctmModel.getMethodList().size();
		//メソッドRow追加
		insertRows(methodlastRow, methodSize, sheet, METHOD);

		// メソッドを設定
		for (int j = 0; j < methodSize; j++) {
			setRowInfo(ctmModel, sheet, j, cellStyle, METHOD);
		}
	}

	//メソッドのヘーダ部のフォーマットを設定
	private void createMethodHead(Sheet sheet) {
		CellRangeAddress region1 = new CellRangeAddress(methodfirstRow - 2, methodfirstRow - 2, 0, 8);
		sheet.addMergedRegion(region1);
		setRowFormat(sheet, methodfirstRow - 1);
		setRowFormat(sheet, methodfirstRow);
		setRowFormat(sheet, methodfirstRow + 1);
	}

	//共通Rowフォーマットを設定
	private void setRowFormat(Sheet sheet, int rowNum) {
		CellRangeAddress region1 = new CellRangeAddress(rowNum, rowNum, 1, 3);
		CellRangeAddress region2 = new CellRangeAddress(rowNum, rowNum, 4, 6);
		CellRangeAddress region3 = new CellRangeAddress(rowNum, rowNum, 7, 8);
		sheet.addMergedRegion(region1);
		sheet.addMergedRegion(region2);
		sheet.addMergedRegion(region3);
	}

	//共通情報を設定
	private void setClassCommonFiled(ClassToExcelModel ctmModel, Sheet sheet) {
		// パッケージ名を設定
		sheet.getRow(3).getCell(2).setCellValue(ctmModel.getFieldPackageNm());
		// クラス名（物理）を設定
		sheet.getRow(4).getCell(2).setCellValue(ctmModel.getFieldClassPhysicsNm());
		// スコープ／修飾子を設定
		sheet.getRow(5).getCell(2).setCellValue("public");
		// 継承クラスを設定
		sheet.getRow(6).getCell(2).setCellValue(ctmModel.getFieldImplClassNm());
		// アノテーションを設定
		sheet.getRow(5).getCell(7).setCellValue(ctmModel.getFieldAnnotation());
		// 実装インタフェースを設定
		sheet.getRow(6).getCell(7).setCellValue(ctmModel.getFieldInterface());
		// 概要を設定
		sheet.createRow(8).createCell(0).setCellValue(ctmModel.getFieldClassInfo());
		// 備考を設定
		sheet.createRow(14).createCell(0).setCellValue(ctmModel.getFieldTopRemarks());
	}

	//行情報を設定
	private void setRowInfo(ClassToExcelModel ctmModel, Sheet sheet, int i, CellStyle style, String type) {
		HSSFRow row = (HSSFRow) sheet.getRow(fieldfirstRow + i);
		if (METHOD.equals(type)) {
			MethodListDTO method = ctmModel.getMethodList().get(i);
			row = (HSSFRow) sheet.getRow(methodfirstRow + i);
			// メソッド定義を設定
			row.createCell(1).setCellValue(method.getMethodDefinition());
			// メソッド概要を設定
			row.createCell(4).setCellValue(method.getMethodSummary());
			// 備考を設定
			row.createCell(7).setCellValue(method.getFootRemarks());
		} else {
			FieldListDTO fld = ctmModel.getFieldList().get(i);
			// フィールド定義を設定
			row.createCell(1).setCellValue(fld.getFieldDefinition());
			// フィールド概要を設定
			row.createCell(4).setCellValue(fld.getFieldSummary());
			// 備考を設定
			row.createCell(7).setCellValue(fld.getFieldmiddleRemarks());
		}

		// 連番を設定
		row.createCell(0).setCellValue(i + 1);
		row.getCell(0).setCellStyle(style);
		row.getCell(1).setCellStyle(style);
		row.createCell(2).setCellStyle(style);
		row.createCell(3).setCellStyle(style);
		row.getCell(4).setCellStyle(style);
		row.createCell(5).setCellStyle(style);
		row.createCell(6).setCellStyle(style);
		row.getCell(7).setCellStyle(style);
		row.createCell(8).setCellStyle(style);

	}

	private CellStyle getCellStyle(Workbook wb) {
		CellStyle cellStyle = wb.createCellStyle();

		cellStyle.setBorderBottom(BorderStyle.THIN);
		cellStyle.setBottomBorderColor(HSSFColor.BLACK.index);

		cellStyle.setBorderLeft(BorderStyle.THIN);
		cellStyle.setLeftBorderColor(HSSFColor.BLACK.index);

		cellStyle.setBorderTop(BorderStyle.THIN);
		cellStyle.setTopBorderColor(HSSFColor.BLACK.index);

		cellStyle.setBorderRight(BorderStyle.THIN);
		cellStyle.setRightBorderColor(HSSFColor.BLACK.index);
		return cellStyle;
	}

	private void insertRows(int startRow, int rowcount, Sheet sheet, String type) {

		List<CellRangeAddress> list = new ArrayList<>();
		list.addAll(sheet.getMergedRegions());

		for (Iterator<CellRangeAddress> iterator = list.iterator(); iterator.hasNext();) {
			CellRangeAddress cellRange = iterator.next();
			if (cellRange.getFirstRow() > fieldlastRow) {
				sheet.addMergedRegion(new CellRangeAddress(cellRange.getFirstRow() + rowcount,
						cellRange.getFirstRow() + rowcount, cellRange.getFirstColumn(), cellRange.getLastColumn()));
			}
		}

		for (int i = 0; i < rowcount; i++) {
			sheet.createRow(startRow + i);
			sheet.shiftRows(startRow + i, sheet.getLastRowNum(), 1, true, false);
			setRowFormat(sheet, startRow + i);

			if (METHOD.equals(type)) {
				methodlastRow++;
			} else {
				fieldlastRow++;
				methodfirstRow++;
				methodlastRow++;
			}
		}
	}
}
